home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_400 / 423_01 / recio200 / recio.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-04-15  |  13.3 KB  |  390 lines

  1. /*****************************************************************************
  2.    MODULE: recio.c
  3.   PURPOSE: recio primary functions
  4. COPYRIGHT: (C) 1994 William Pierpoint
  5.  COMPILER: Borland C Version 3.1
  6.        OS: MSDOS Version 6.2
  7.   VERSION: 2.00
  8.   RELEASE: April 15, 1994
  9. *****************************************************************************/
  10.  
  11. #include <ctype.h>
  12. #include <errno.h>
  13. #include <float.h>
  14. #include <limits.h>
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <string.h>
  18.  
  19. #include "recio.h"
  20.  
  21. #define rcol(rp)         ((rp)->r_colno)
  22. #define rflags(rp)       ((rp)->r_flags)
  23. #define rfd(rp)          ((rp)->r_fd)
  24. #define rfp(rp)          ((rp)->r_fp)
  25. #define rreclen(rp)      ((rp)->r_reclen)
  26. #define rrecsiz(rp)      ((rp)->r_recsiz)
  27. #define rfldsiz(rp)      ((rp)->r_fldsiz)
  28. #define rfldch(rp)       ((rp)->r_fldch)
  29. #define rtxtch(rp)       ((rp)->r_txtch)
  30.  
  31. /* private module variables */
  32. static REC *_RECS = NULL;              /* ptr to array of REC structures */
  33.  
  34. static REC rin  = { 1,      0,    stdin,  "stdin",     0L,
  35.                     0,      0,        0,        0,   NULL, 
  36.                     0,   NULL, RECFLDCH, RECTXTCH,  RECIN };
  37.  
  38. static REC rout = { 2, _R_WRT,   stdout, "stdout",     0L, 
  39.                     0,      0,        0,        0,   NULL, 
  40.                     0,   NULL, RECFLDCH, RECTXTCH, RECOUT };
  41.  
  42. static REC rerr = { 3, _R_WRT,   stderr, "stderr",     0L, 
  43.                     0,      0,        0,        0,   NULL, 
  44.                     0,   NULL, RECFLDCH, RECTXTCH, RECERR };
  45.  
  46. #if defined (__MSDOS__) || (MSDOS)
  47. static REC rprn = { 4, _R_WRT,   stdprn, "stdprn",     0L, 
  48.                     0,      0,        0,        0,   NULL, 
  49.                     0,   NULL, RECFLDCH, RECTXTCH, RECPRN };
  50. #define NREC      4          /* number of static record streams */
  51. #else
  52. #define NREC      3
  53. #endif
  54. #define ROPEN_MIN NREC       /* reserved for recin, etc */
  55. #define ROPEN     max(ROPEN_MAX, ROPEN_MIN)
  56.  
  57. /* public variables */
  58. REC *recin = &rin;
  59. REC *recout = &rout;
  60. REC *recerr = &rerr;
  61. #if defined (__MSDOS__) || (MSDOS)
  62. REC *recprn = &rprn;
  63. #endif
  64.  
  65. /* friend variables */
  66. char _r_nsbuf[NSBUFSIZ];     /* buffer for numeric to string conversions */
  67.  
  68. /* Support functions */
  69. /****************************************************************************/
  70. static void                  /* returns nothing                             */
  71.     _rexit(                  /* at program exit, clean up                   */
  72.         void)                /* no arguments                                */
  73. /****************************************************************************/
  74. {
  75.     /* free recin buffers */
  76.     free(rflds(recin));
  77.     free(rrecs(recin));
  78.     rflds(recin) = NULL;
  79.     rfldsiz(recin) = 0;
  80.     rrecs(recin) = NULL;
  81.     rrecsiz(recin) = 0;
  82.     rreclen(recin) = 0;
  83.  
  84.     /* ensure all record streams closed */
  85.     rcloseall();
  86. }
  87.  
  88. /****************************************************************************/
  89. void                         /* return error number (0=no error)            */
  90.     _rsetexitfn(             /* register _rexit function with atexit()      */
  91.         REC *rp)             /* record pointer                              */
  92. /****************************************************************************/
  93. {
  94.     static int once=0;       /* register exit fn only once */
  95.  
  96.     if (!once) {
  97.  
  98.         /* execute this path at most one time */
  99.         once++;
  100.  
  101.         /* if atexit() fails to register _rexit() function */
  102.         if (atexit(_rexit)) {
  103.  
  104.            /* register warning */
  105.            rsetwarn(rp, R_WNOREG);
  106.         }
  107.     }
  108.  
  109. /****************************************************************************/
  110. int                          /* return error number (0=no error)            */
  111.     _rstatus(                /* check stream for errors                     */
  112.         REC *rp,             /* record pointer                              */
  113.         int mode)            /* mode (0=read; !0=write/append)              */
  114. /****************************************************************************/
  115. {
  116.     int errnum=0;            /* error number */
  117.     int smode;               /* stream mode */
  118.  
  119.     /* test for valid record pointer */
  120.     if (!risvalid(rp)) {
  121.         errnum = rseterr(NULL, EINVAL);
  122.         goto done;
  123.     }
  124.     
  125.     /* if stream _R_WRT flag does not match mode */
  126.     smode = rflags(rp) & _R_WRT;
  127.     if ((mode && !smode) || (!mode && smode)) {
  128.         errnum = rseterr(rp, R_EINVMOD);
  129.         goto done;
  130.     }
  131.  
  132.     /* if record 0 and write mode */
  133.     if (!rrecno(rp) && mode) {
  134.         rrecno(rp)++;
  135.     }
  136.  
  137.     /* test for previous error */
  138.     errnum = rerror(rp);
  139.  
  140. done:
  141.     return (errnum);
  142. }
  143.  
  144. /****************************************************************************/
  145. static void                  /* returns nothing                             */
  146.     _rfree(                  /* free the memory allocated to a record       */
  147.         REC *rp)             /* record pointer                              */
  148. /****************************************************************************/
  149. {
  150.     if (risvalid(rp)) {
  151.         free(rflds(rp));
  152.         free(rrecs(rp));
  153.         if (rfp(rp))   fclose(rfp(rp));
  154.         memset(rp, 0, sizeof(REC));
  155.     }
  156. }
  157.  
  158. /* User functions */
  159. /****************************************************************************/
  160. REC *                        /* return record pointer                       */
  161.     ropen(                   /* open a record stream for reading            */
  162.         const char *fname,   /* name of file to open                        */
  163.         const char *mode)    /* type of mode used to open file              */
  164. /****************************************************************************/
  165. {
  166.     REC *rp = _RECS;         /* record pointer */
  167.     int  i;                  /* count of REC structures */
  168.     int  ch;                 /* first character of mode */
  169.     
  170.     /* only modes currently supported are "r", "w", and "a" */
  171.     ch = tolower(*mode);
  172.     if (!(ch=='r' || ch=='w' || ch=='a')) {
  173.         rp = NULL;
  174.         rseterr(NULL, EINVAL);
  175.         goto done;
  176.     }
  177.  
  178.     /* allocate memory for array of REC structures */
  179.     if (!rp) {
  180.         do {
  181.             /* note: no memory allocation needed for recin, etc */
  182.             rp = _RECS = (REC *) calloc(ROPEN-NREC, sizeof(REC));
  183.             if (!rp) {
  184.                 if (rseterr(NULL, ENOMEM)) goto done;
  185.             }
  186.         } while (!rp);
  187.     }
  188.  
  189.     /* search thru REC structures until empty position found */
  190.     for (i=NREC+1; i <= ROPEN; i++, rp++) {
  191.         if (!rfd(rp)) {
  192.             rfd(rp) = i;
  193.             break;
  194.         }
  195.     }
  196.     /* error if out of positions */
  197.     if (i > ROPEN) {
  198.         rp = NULL;
  199.         rseterr(NULL, EMFILE);
  200.         goto done;
  201.     }
  202.  
  203.     /* open file */
  204.     rfp(rp) = fopen(fname, mode);
  205.     if (!rfp(rp)) {
  206.         rclose(rp);
  207.         rp = NULL;
  208.         /* if error other than path/file not found */
  209.         if (errno != ENOENT) {
  210.             rseterr(NULL, errno);
  211.         }
  212.         goto done;
  213.     }
  214.  
  215.     /* initialize */
  216.     if (ch != 'r') rflags(rp)  |= _R_WRT;
  217.     rnames(rp)  = fname;
  218.     rrecno(rp)  = 0L;
  219.     rfldno(rp)  = 0;
  220.     rcol(rp)    = 0;
  221.     rrecsiz(rp) = 0;
  222.     rreclen(rp) = 0;
  223.     rrecs(rp)   = NULL;
  224.     rfldsiz(rp) = 0;
  225.     rflds(rp)   = NULL;
  226.     rfldch(rp)  = RECFLDCH;
  227.     rtxtch(rp)  = RECTXTCH;
  228.     _rsetexitfn(rp);
  229.  
  230. done:
  231.     return (rp);
  232. }
  233.  
  234. /****************************************************************************/
  235. int                          /* return error number (0=no error)            */
  236.     rclose(                  /* close a record stream                       */
  237.         REC *rp)             /* record pointer                              */
  238. /****************************************************************************/
  239. {
  240.     int errnum=0;            /* error number (0=no error) */
  241.     int i;                   /* count REC structures */
  242.     REC *recp=_RECS;         /* pointer to _RECS array */
  243.  
  244.     if (risvalid(rp)) {
  245.         /* close record stream, but not recin, recout, recerr */
  246.         if (rfd(rp) > NREC) _rfree(rp);
  247.  
  248.         /* if all record streams closed, free _RECS */
  249.         /* note: valid rp implies valid recp */
  250.         for (i=NREC+1; i <= ROPEN; i++, recp++) {
  251.             if (rfd(recp)) goto done;
  252.         }
  253.         free(_RECS);
  254.         _RECS = NULL;
  255.  
  256.     } else {
  257.         errnum = rseterr(NULL, EINVAL);
  258.     }
  259.  
  260. done:
  261.     return (errnum);
  262. }
  263.  
  264. /****************************************************************************/
  265. int                          /* returns number of streams closed            */
  266.     rcloseall(               /* close all record streams                    */
  267.         void)                /* no arguments                                */
  268. /****************************************************************************/
  269. {
  270.     int num=0;               /* number of streams closed */
  271.     int i;                   /* count REC structures */
  272.     REC *recp=_RECS;         /* pointer to _RECS array */
  273.  
  274.     /* close every open record stream, except recin, etc */
  275.     if (recp) {
  276.         for (i=NREC+1; i <= ROPEN; i++, recp++) {
  277.             if (rfd(recp)) {
  278.                 _rfree(recp);
  279.                 num++;
  280.             }
  281.         }
  282.         free(_RECS);
  283.         _RECS = NULL;
  284.     }
  285.     return (num);
  286. }
  287.  
  288. /****************************************************************************/
  289. int                          /* return !0 for valid; 0 for invalid          */
  290.     risvalid(                /* is record pointer valid?                    */
  291.         REC *rp)             /* record pointer                              */
  292. /****************************************************************************/
  293. {
  294.     int valid=1;             /* validation state (!0=valid) */
  295.  
  296.     /* if rp is null pointer or rfd not between 1 and ROPEN */
  297.     if (!rp || rfd(rp) < 1 || rfd(rp) > ROPEN) {
  298.         /* invalid record pointer */
  299.         valid = 0;
  300.     }
  301.     return (valid);
  302. }
  303.  
  304. /****************************************************************************/
  305. int                          /* return error number (0=no error)            */
  306.     rsetfldch(               /* set field separator character               */
  307.         REC *rp,             /* record pointer                              */
  308.         int  ch)             /* field separator character                   */
  309. /****************************************************************************/
  310. {
  311.     int errnum=0;            /* error number (0=no error) */
  312.  
  313.     if (risvalid(rp)) {
  314.         if (isascii(ch)) {
  315.             rfldch(rp) = ch;
  316.         } else {
  317.             errnum = rseterr(rp, R_EINVAL);
  318.         }
  319.     } else {
  320.         errnum = rseterr(NULL, EINVAL);
  321.     }
  322.     return (errnum);
  323. }
  324.  
  325. /****************************************************************************/
  326. int                          /* return error number (0=no error)            */
  327.     rsettxtch(               /* set text string delimiter character         */
  328.         REC *rp,             /* record pointer                              */
  329.         int  ch)             /* text delimiter character                    */
  330. /****************************************************************************/
  331. {
  332.     int errnum=0;            /* error number (0=no error) */
  333.  
  334.     if (risvalid(rp)) {
  335.         if (isascii(ch)) {
  336.             rtxtch(rp) = ch;
  337.         } else {
  338.             errnum = rseterr(rp, R_EINVAL);
  339.         }
  340.     } else {
  341.         errnum = rseterr(NULL, EINVAL);
  342.     }
  343.     return (errnum);
  344. }
  345.  
  346. /****************************************************************************/
  347. int                          /* return 0 on success; errnum on error        */
  348.     rsetcxtno(               /* set context number of record stream         */
  349.         REC *rp,             /* record pointer                              */
  350.         int  cxtno)          /* context number                              */
  351. /****************************************************************************/
  352. {
  353.     int errnum=0;            /* error number (0=no error) */
  354.  
  355.     if (risvalid(rp)) {
  356.         if (rcxtno(rp) >= 0  && cxtno >= 0) {
  357.             rcxtno(rp) = cxtno;
  358.         } else {
  359.             errnum = rseterr(rp, R_EINVAL);
  360.         }
  361.     } else {
  362.         errnum = rseterr(NULL, EINVAL);
  363.     }
  364.     return (errnum);
  365. }
  366.  
  367. /****************************************************************************/
  368. int                          /* return 0 on success; errnum on error        */
  369.     rsetbegcolno(            /* set beginning record column number          */
  370.         REC *rp,             /* record pointer                              */
  371.         int  colno)          /* first column in record is 0 or 1            */
  372. /****************************************************************************/
  373. {
  374.     int errnum=0;            /* error number (0=no error) */
  375.  
  376.     if (risvalid(rp)) {
  377.         if (colno == 1) {
  378.             rflags(rp) |= _R_COL;
  379.         } else if (colno == 0) {
  380.             rflags(rp) &= ~_R_COL;
  381.         } else {
  382.             errnum = rseterr(rp, R_EINVAL);
  383.         }
  384.     } else {
  385.         errnum = rseterr(NULL, EINVAL);
  386.     }
  387.     return (errnum);
  388. }
  389.